from django.contrib.auth.models    import AnonymousUser
from django.core.exceptions        import ObjectDoesNotExist,MultipleObjectsReturned
from django.db.models              import Q
from sitepal.sitebase.conf         import properties
from sitepal.sitemenu.models.flags import MENU_LINKS_TO_PARENT,MENU_VISIBLE_IN_TREE
from sitepal.sitemenu.validators   import PathValidator

def filter_menu_tree_links(links,user):
    user = user or AnonymousUser()
    
    def do_filter(link):
        return (user.has_perm('sitemenu.call_menuview',link.view) and
                link.view.type_flags & MENU_VISIBLE_IN_TREE)

    return filter(do_filter,links)

def get_ancestor_paths(path):
    assert isinstance(path,basestring)
    parts     = PathValidator.RE_SPLIT.split(path)
    length    = len(parts)-1
    end       = (1 << len(parts))-1
    ancestors = []
    for mask in properties.get('menu-views-parts-fit-masks',admin=True):
        if mask > end:
            continue
        elif mask < (1 << length):
            length -= 1
        items = []
        for index in reversed(xrange(0,length+1)):
            if mask & (1 << index):
                items.append(parts[length - index])
            else:
                items.append('%')
        ancestors.append('/'.join(items))
    return tuple(ancestors)

def get_view_from_name(name):
    from sitepal.sitemenu.models.menuviews import MenuView
    
    assert isinstance(name,basestring)
    try:
        view = MenuView.objects.get(name__exact=name)
    except (ObjectDoesNotExist,MultipleObjectsReturned):
        pass
    return None

def get_view_from_path(path):
    from sitepal.sitemenu.models.menuviews import MenuView
    
    assert isinstance(path,basestring)
    views = MenuView.objects.filter(path__in=get_ancestor_paths(path)
                           ).order_by('-parts_fit')
    if len(views):
        return views[0]
    return None

def get_link_parent_from_path(link):
    from sitepal.sitemenu.models.menulinks import MenuLink
    
    assert isinstance(link,MenuLink)
    if link.path:
        parts = PathValidator.RE_SPLIT.split(link.path)
        if len(parts) > 1:
            for i in xrange(1,len(parts)):
                parent_path = "/".join(parts[:-i])
                try:
                    if link.origin != '[user]':
                        return link._default_manager.get(Q(path__exact=parent_path),
                                                        ~Q(origin__exact='[user]'))
                    else:
                        return link._default_manager.get(path=parent_path,menu=link.menu)
                    break
                except ObjectDoesNotExist:
                    pass
    return None

def get_from_cache_or_load(label,cache,lookup,threshold=512):
    if label in cache:
        obj = cache[label]
    else:
        obj          = lookup(label)
        cache[label] = obj
        if len(cache.keyOrder) >= threshold:
            key = cache.keyOrder[0]
            del cache[key]
    return obj

